﻿using Abp.Authorization;
using Abp.BackgroundJobs;
using Abp.Domain.Repositories;
using Abp.Extensions;
using ARchGL.Platform.BackgroundWorker;
using ARchGL.Platform.Core;
using ARchGL.Platform.Juneng;
using ARchGL.Platform.Organizations;
using ARchGL.Platform.Utils;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ARchGL.Platform.Application
{
    /// <summary>
    /// 报表服务 实现
    /// </summary>
    [AbpAuthorize]
    public class ReportsAppService : PlatformAppServiceBase, IReportsAppService
    {
        private readonly IRepository<Notices, Guid> noticesRepository;
        private readonly IRepository<NoticesUsers, Guid> noticesUsersRepository;
        private readonly IRepository<Projects, Guid> projectsRepository;
        private readonly IOrganizationUnitAppService organizationUnitAppService;
        private readonly IRepository<SelfChecks, Guid> selfChecksRepository;
        private readonly IRepository<SecurityChecks, Guid> securityChecksRepository;
        private readonly IRepository<SecurityCheckItems, Guid> securityCheckItemsRepository;
        private readonly IRepository<UserLoginAttemptExtend, long> userLoginAttemptExtendRepository;
        private readonly IBackgroundJobManager backgroundJobManager;
        private static TimerCache<Dictionary<string, Dictionary<string, int[]>>> ChecksMonthReportCache = new TimerCache<Dictionary<string, Dictionary<string, int[]>>>();
        private static TimerCache<Dictionary<int?, int?>> LoginTypeReportCache = new TimerCache<Dictionary<int?, int?>>();

        public ReportsAppService(IRepository<Notices, Guid> _noticesRepository, IRepository<NoticesUsers, Guid> _noticesUserRepository,
            IRepository<Projects, Guid> _projectsRepository, IRepository<SecurityChecks, Guid> _securityChecksRepository,
            IRepository<SelfChecks, Guid> _selfChecksRepository, IRepository<SecurityCheckItems, Guid> _securityCheckItemsRepository,
            IRepository<UserLoginAttemptExtend, long> _userLoginAttemptExtendRepository,
            IBackgroundJobManager _backgroundJobManager,
            IOrganizationUnitAppService _organizationUnitAppService)
        {
            noticesRepository = _noticesRepository;
            noticesUsersRepository = _noticesUserRepository;
            projectsRepository = _projectsRepository;
            selfChecksRepository = _selfChecksRepository;
            securityChecksRepository = _securityChecksRepository;
            securityCheckItemsRepository = _securityCheckItemsRepository;
            organizationUnitAppService = _organizationUnitAppService;
            userLoginAttemptExtendRepository = _userLoginAttemptExtendRepository;
            backgroundJobManager = _backgroundJobManager;
        }

        #region 巡检/自检

        #endregion

        /// <summary>
        /// 获取 巡检/自检 完成状态月报表，10分钟缓存
        /// </summary>
        /// <returns></returns>
        public async Task<Dictionary<string, Dictionary<string, int[]>>> QueryChecksMonthReport()
        {
            return await ChecksMonthReportCache.GetAsync(3600, async () =>
            {
                var checkDict = await InitDict();
                var checkList = from sc in securityChecksRepository.GetAll() select new { sc.Status, sc.CreationTime };
                foreach (var item in checkList)
                {
                    var date = item.CreationTime.ToString("yyyy-MM");
                    var index = item.Status != EnumCheckAndFeedbackStatus.已完成 ? 0 : 1;
                    if (checkDict.ContainsKey(date))
                        checkDict[date][index] += 1;
                    else
                        checkDict.Add(date, new int[2]);
                }

                var selfDict = await InitDict();
                var selfList = from sc in selfChecksRepository.GetAll() select new { sc.Status, sc.CreationTime };
                foreach (var item in selfList)
                {
                    var date = item.CreationTime.ToString("yyyy-MM");
                    var index = item.Status != EnumSelfCheckStatus.已整改 ? 0 : 1;
                    if (selfDict.ContainsKey(date))
                        selfDict[date][index] += 1;
                    else
                        selfDict.Add(date, new int[2]);
                }

                var dict = new Dictionary<string, Dictionary<string, int[]>>
                 {
                    { "check", checkDict }, //自检
                    { "self", selfDict } //巡检
                 };
                return await Task.FromResult(dict);
            });
        }

        /// <summary>
        /// 巡检 完成/未完成 概况，10分钟缓存
        /// </summary>
        /// <param name="input">项目标识</param>
        /// <returns>类型名称，int[] { 完成,未完成 }</returns>
        public async Task<Dictionary<string, int[]>> QueryChecksOverview(Guid input)
        {
            var dict = new Dictionary<string, int[]>();
            try
            {
                var key = CleanExpireCacheWorker.ChecksOverviewCache.Keys.FirstOrDefault(x => x.Contains(input.ToString()));

                if (!key.IsNullOrWhiteSpace())
                    return CleanExpireCacheWorker.ChecksOverviewCache[key];

                dict = await GetChecksOverview(input);
                CleanExpireCacheWorker.ChecksOverviewCache.TryAdd(input + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"), dict);
            }
            catch { }
            return dict;
        }

        /// <summary>
        /// 获取 登录类型报表，10分钟缓存
        /// </summary>
        /// <returns></returns>
        public async Task<Dictionary<int?, int?>> QueryLoginTypeReport()
        {
            return await LoginTypeReportCache.GetAsync(3600, async () =>
            {
                var dict = new Dictionary<int?, int?>();
                var list = from ul in userLoginAttemptExtendRepository.GetAll()
                           where ul.Type != null
                           group ul by ul.Type into x
                           select new
                           {
                               x.Key,
                               Count = x.Count()
                           };

                return await list.ToDictionaryAsync(x => x?.Key, x => x?.Count);
            });
        }

        #region Private method

        private async Task<Dictionary<string, int[]>> InitDict()
        {
            var dict = new Dictionary<string, int[]>();
            for (int i = 12; i >= 0; i--)
            {
                dict.Add(DateTime.Now.AddMonths(i * -1).ToString("yyyy-MM"), new int[2]);
            }
            return await Task.FromResult(dict);
        }

        private async Task<Dictionary<string, int[]>> GetChecksOverview(Guid input)
        {
            var checkItemList = await securityCheckItemsRepository.GetAllListAsync(x => x.ProjectId == input && x.ParentId == Guid.Empty);
            var dict = new Dictionary<string, int[]>();
            var list = await (from sc in securityChecksRepository.GetAll()
                              where sc.ProjectId == input
                              select new
                              {
                                  sc.CheckItemId,
                                  sc.Status,
                              }).ToListAsync();

            foreach (var item in list)
            {
                var name = checkItemList.GetNameOrEmpty(item.CheckItemId);
                var index = item.Status == EnumCheckAndFeedbackStatus.已完成 ? 0 : 1;
                if (dict.ContainsKey(name))
                    dict[name][index] += 1;
                else
                {
                    var val = new int[2];
                    val[index] = 1;
                    dict.Add(name, val);
                }
            }

            return dict;
        }

        #endregion
    }
}
